/*
keyframe.esKeyFrameNivel = false;
keyframe.esKeyFramePiso = false;
keyframe.esKeyFrameSpace = false;
keyframe.punteroNivel = null;
keyframe.punteroPlano = null;
keyframe.punteroNodo = null; //puede apuntar tanto 
 * */

var _lineaAnimada = null; //esta linea se mantiene mientras se dibuja la linea dentro de un piso TODO: aclaracion xq?


//var tweens = null;
//este objeto se encarga de la animacion de un camino
function dibujadorCaminos(){
	
	//+++++++++++++++ ++++++++++++++ ++++++++++++++++
	//+++++++++++++++ INICIALIZACION ++++++++++++++++
	//+++++++++++++++ ++++++++++++++ ++++++++++++++++
	
	var _this = this;
	var _lineasCreadas =[]; //lineas que forman parte del camino que estoy animando separadas por pisos
	
	//PARAMS mantiene las propiedades de la animacion
	var PARAMS = {
			velocidadLinea : CONSTANTS.VELOCIDAD_LINEA,//100/1000; //unidades por segundo
            velocidadRepCamara : (CONSTANTS.VELOCIDAD_POSICIONAMIENTO_CAMARA == undefined)? 100/1000 : CONSTANTS.VELOCIDAD_POSICIONAMIENTO_CAMARA,
            velocidadRepCamaraPrincipio : (CONSTANTS.VELOCIDAD_POSICIONAMIENTO_CAMARA_PRINCIPIO== undefined)? 100/1000 : CONSTANTS.VELOCIDAD_POSICIONAMIENTO_CAMARA_PRINCIPIO,
            ralentizar_anim_escaleras : CONSTANTS.RALENTIZAR_ANIM_ESCALERAS, //variable que hace que la animacion en las escaleras se X veces mas lenta que en el resto de la animacion
            distancia_a_objetivo : CONSTANTS.DISTANCIA_VERTICAL_CAMARA_PLANO,//300; //antes se llamaba: _distancia_vertical_camara_plano: altura de la camara cuando esta a 90�
            tiempo_posicionamiento_camara : CONSTANTS.TIEMPO_POSICIONAMIENTO_CAMARA,
            distancia_a_escalera :  CONSTANTS.DISTANCIA_A_ESCALERA,
            distancia_linea_a_plano : CONSTANTS.DISTANCIA_LINEA_A_PLANO,
	};
	
	var _PANEL_CAMINOS = new panelCaminos("divCamino","panelCamino");
	var _MANAGER_GALERIA = new managerGaleria("linksGalleria");
	var _TWEENER = new TWEENER(PARAMS);
	var _ESTADO = new estadoAnimacion();
	var _UI_PANEL_PLAYBACK = new UI_panel_playback(_ESTADO);//inicializa los componentes graficos del panel de animacion
	//var _scene = WEBGL.getScene();
	
	var _listaFrames = []; //mantiene la lista de puntos a animar (todos: comunes y keyframes)

	//var _controlCamaraFly = WEBGL.getCameraControls();

	
	
	//ESTADO ANIMACION. DECLARACION Y METODOS SET Y GET
	//dep: this.getActualKeyframe = function(){return _ESTADO.frameActual;};
	this.getTiposAnimacion = function(){return _ESTADO.getTiposAnimacion();};
	this.setTipoAnimacion = function(tipo){_ESTADO.setTipoAnimacion(tipo);};
	
	this.getTiposAnimacionCamara = function(){return _ESTADO.getTiposAnimacionCamara();};
	this.setTipoAnimacionCamara = function(tipo){_ESTADO.setTipoAnimacionCamara(tipo);};
	this.getTiposAnimacionCamaraActivo = function(){return _ESTADO.getTipoAnimacionCamara();};	
	this.getAnimationState = function(){return _ESTADO.estado;};
	

	this.animarKeyframe = animarKeyframe;//TODO esta es una funcion privada, que la quiero hacer publica
	
	/*deprecated:
	 this.getTiempoPosCamara = function(){return PARAMS.tiempo_posicionamiento_camara;};
     this.setTiempoPosCamara = function(val){ PARAMS.tiempo_posicionamiento_camara = val;};
     this.addTiempoPosCamara = function(val){ PARAMS.tiempo_posicionamiento_camara  = eval(PARAMS.tiempo_posicionamiento_camara + val); return PARAMS.tiempo_posicionamiento_camara;};
     
     this.getVelReposCamara = function(){return PARAMS.velocidadRepCamara;};
     this.setVelReposCamara = function(val){ PARAMS.velocidadRepCamara = val;};
     this.addVelReposCamara = function(val){ PARAMS.velocidadRepCamara  = eval(PARAMS.velocidadRepCamara + val); return PARAMS.velocidadRepCamara;};
	*/
	//+++++++++++++++ ++++++++++++++++++ ++++++++++++++++
	//+++++++++++++++ FIN INICIALIZACION ++++++++++++++++
	//+++++++++++++++ ++++++++++++++++++ ++++++++++++++++
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//------------------------------------------- CREATE ANIMATION --------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//setea las condiciones iniciales para comenzar con la animacion del camino
	//<path>  : camino a animar (TODO definir formato)
	//<arbol> : estructura jerarquica de la informacion acerca de las edificios/pisos/aulas_u_oficinas
	this.createAnimation = function(camino){

		cleanAnimation();
		
		//"acomodo" la lista de keyframes
		procesarCamino(camino);
	
		_TWEENER.tweenBuilder.setListaFrames(_listaFrames);
		_TWEENER.tweenBuilder.setEstadoAnimacion(_ESTADO);
		_TWEENER.tweenBuilder.setControlCamara(_controlCamaraFly);
		
		//---------------------------------<<COMPLEMENTOS>>---------------------------------
		//<<creamos los complementos: divCamino y galeria De imagenes>> 
		//funcion al clickear el boton (camarita), en el panel de spaces, para ver una imagen del lugar
		var _manG = _MANAGER_GALERIA;
		var clickBotonGaleria = function(){
			var _frameAct = $(this).attr("valor"); //saco el valor de un atributo que almaceno en el boton
			_manG.open(_frameAct);
		};
			
		//creamos el listado de spaces para recomenzar la animacion desde un cierto punto
		//y el listado de links a las imagenes para la galeria de aulas
		var dataParaComplementos = [];
		for (var i in _listaFrames){
			if (_listaFrames[i].esKeyFrameSpace	&& 	_listaFrames[i].nombre != "dummy")	//TODO ver 27/11		
			{
				dataParaComplementos.push({value: i, texto: _listaFrames[i].nombre});
			}
		}
		
		_PANEL_CAMINOS.generarPanel(dataParaComplementos, clickBotonGaleria);
		_MANAGER_GALERIA.generarGaleria(dataParaComplementos);
		dataParaListaCaminos = null; //GC
		//<<fin creacion de complementos>>
		//---------------------------------<<COMPLEMENTOS>>---------------------------------
		
		_ESTADO.estado = "stopped";
		_UI_PANEL_PLAYBACK.setUpUI();
		
	};

	
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//------------------------------------------- CLEAN ANIMATION ---------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//elimina las lineas de animaciones anteriores
	//y realiza los seteos para realizar una nueva animacion
	function cleanAnimation(){
		$("#panelCamino").hide();
		WEBGL.mostrarEscena(true); //TODO
		
		_this.stopAnimation();
		_listaFrames = null;
		_listaFrames = [];
		
		//deshabilito botones
		_UI_PANEL_PLAYBACK.disableButtons();
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//-------------------------------------------- PAUSE ANIMATION --------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.pauseAnimation = function(){
		WEBGL.mostrarEscena(true); //TODO
		
		_TWEENER.tweenPlayBack.pauseTweens();
		_ESTADO.estado = "paused"; 
		_UI_PANEL_PLAYBACK.updatePlayPauseButton();
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//-------------------------------------------- RESUME ANIMATION -------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.resumeAnimation = function(){
		WEBGL.mostrarEscena(false); //TODO
		 
		 _TWEENER.tweenPlayBack.resumeTweens();
		 _ESTADO.estado = "playing";
		 _UI_PANEL_PLAYBACK.updatePlayPauseButton();
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//--------------------------------------------- STOP ANIMATION --------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.stopAnimation = function(noModificarFrameActual){ //TODO noModificarFrameActual
		
		WEBGL.mostrarEscena(true); //TODO
		_TWEENER.tweenBuilder.setMantenerCamara3D(false);

		limpiarEsc();//limpiamos la escena
		
		_lineasCreadas = null;
		_lineasCreadas =[];
		
		_TWEENER.tweenPlayBack.flushTweens();
		if (!noModificarFrameActual){
			_ESTADO.reiniciar(); //asigna el estado "stopped"
			_PANEL_CAMINOS.rewind();
		}
		_UI_PANEL_PLAYBACK.updatePlayPauseButton();
		
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//--------------------------------------------- PLAY ANIMATION --------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.playAnimation = function(keyy){ //deprecated: parametro key

			if (!_listaFrames.length) return;	
		
			if (_ESTADO.estado == "stopped"){
				if (_ESTADO.frameActual == null || _ESTADO.frameActual>=_listaFrames.length){//TODO para debug
					this.stopAnimation();//TODO
				}else{
					this.stopAnimation(true);
					//alert("frame act: "+_ESTADO.frameActual);
				}
			}
			
			if (_ESTADO.estado == "paused"){
				this.resumeAnimation();
				return;
			}
			
			var key = (keyy == undefined || keyy == null)? _ESTADO.frameActual : keyy;
			if (key == _listaFrames.length ){ key--;}
//			if (key == _listaFrames.length-1 ){ key--;}
			
			var key_mas_1 = Number(key) + 1; //Unbeliavable: si no le pongo 'Number', me toma key como un string. TODO: debug
			//alert("key_mas_1->"+key_mas_1);

			if (key > 0){
				//console.log("key == 0. voy a simular con key:",key);
				animarKeyframeSimulado(key);
			}
			//if (key == 0){key++;}
			//console.log("pase el if de simulado con key:",key);
		
			WEBGL.mostrarEscena(false);		////muestra u oculta la escena (obj) del frente de la universidad
			_ESTADO.actualizarEstado("playing");
			_UI_PANEL_PLAYBACK.updatePlayPauseButton();
		
			var callback = function(){
				if (CONSTANTS.FLECHAS_CAMINO_ENABLED && key == 0){
					var tween = null;
					var duracion = 1000;
					tween = _TWEENER.tweenBuilder.getTweenMarcador("inicial",duracion);
					tween.start();
				}
				animarKeyframe(key_mas_1); 
			};
			//console.log("estoy por reposicionar la camara con key:",key);
			resposicionarCamara(key, callback);
		
	};
	

	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
//-------------------------------------------------------------------------------------------------------------	
	
	
	
	
	//retorna los elementos de la escena que han sido modificados, a su estado normal
	//por ej: color de las escaleras
	function limpiarEsc(){
		
		//hago desaparecer las flechas que indican el comienzo y fin del camino
		//WEBGL.getMarcadorInicio().visible = false;
		//WEBGL.getMarcadorFinal().visible = false;		
		
		//remuevo todas las lineas generadas en animaciones anteriores
		for (var i = 0; i < _lineasCreadas.length; i++){
			_scene.remove(_lineasCreadas[i]); //TODO
		}
		
		if (_ESTADO.frameActual != null ){
			
			var l = _ESTADO.frameActual;
			if (_ESTADO.frameActual >= _listaFrames.length){
				l = _listaFrames.length - 1;
			}
			
			//restauro el color original de las escaleras (se pintan de distinto color al animarse)
			for (var i = 0; i <= l; i++){
				if (_listaFrames[i].tipo == "escalera"){
					/*
					var escaleraID = _listaFrames[i].punteroNodo;
					var nombreEdificio = _listaFrames[i].punteroEdificio;
					var nombrePiso = _listaFrames[i].punteroPiso;
					var escalera = CONTROLLER_JERARQUIA_SPACES.getPortal3D(nombreEdificio, nombrePiso, escaleraID);//podria llamarse directamente sin pasar el nombre del edificio y el piso (el id del portal deberia ser unico)
					
					if(!escalera) alert('ERROR. animando escalera. controller_playback');
					
					_TWEENER.tweenBuilder.animarColorTween(escalera, CONSTANTS.COLOR_ESCALON_RESTAURAR);//CONSTANTS.COLOR_ESCALON = var global
					*/
					
					_TWEENER.tweenBuilder.restaurarEscalera(i, CONSTANTS.COLOR_ESCALON_RESTAURAR);//CONSTANTS.COLOR_ESCALON = var global
				}
			}
			
		}
	};
	
	//este metodo sirve para reposicionar la camara, por ej cuando se clickea un space en el camino (listado div)
	//newKeyframe es el valor seleccionado(clickeado) desde el panel de spaces
	this.reposicionarCamaraFromDiv = function(newKeyframe){
			
		if (newKeyframe == undefined || isNaN(newKeyframe) || newKeyframe < 0 || newKeyframe > _listaFrames.length){
				alert("error en ANIMATOR.setKeyframe"); //TODO
				return;
		}
		
		limpiarEsc();//limpiamos la escena
		
		_ESTADO.frameActual = newKeyframe;		
		
		_TWEENER.tweenPlayBack.flushTweens();//tengo que limpiar los Tweens en ejecucion
		callback =  function(){	_ESTADO.actualizarEstado("stopped");};
		resposicionarCamara(newKeyframe, callback);
	};
	
	
	
	
	
	
	//reposiciona la camara antes de comenzar una animacion
	//y ejecuta la funcion callback, una vez finalizado el reposicionamiento
	function resposicionarCamara(key, callback){
		var keyInicial = eval(key); //TODO debugging
		
		//01/03
		var puntoTarget = new THREE.Vector3(
				 _listaFrames[keyInicial].x,
				 _listaFrames[keyInicial].z , 
				 _listaFrames[keyInicial].y);
		
		
		var duracionAnimCamara = PARAMS.tiempo_posicionamiento_camara;
		var vectorDireccion = puntoTarget.clone(); //TODO para la animacion look at este no es el punto final
		vectorDireccion.subSelf(_controlCamaraFly.object.position);
		var dist = vectorDireccion.length();
		
	//	console.log("**************************************");
	//	console.log("dist", dist);
		
		var climbY = 0;
		
		var posCamara = _controlCamaraFly.object.position;
		if (posCamara.x == puntoTarget.x
			&&	posCamara.y == puntoTarget.y
			&&	posCamara.z == puntoTarget.z
			){
			duracionAnimCamara = 0;
		}else if(dist > 100){
			duracionAnimCamara = dist/PARAMS.velocidadRepCamaraPrincipio;
			climbY = (dist/3)^4;
		}
		
		var tweenOpacidad = null;
		
		//if (_listaFrames[keyInicial].esKeyFrameNivel){//si estoy en un nivel distinto al que tengo que animar
			var nombreEdificio = _listaFrames[keyInicial].punteroEdificio;
			var nombreNivel = _listaFrames[keyInicial].punteroNivel;
			var tweenOpacidad = _TWEENER.tweenBuilder.cambiarOpacidadNiveles(nombreEdificio, nombreNivel, true, duracionAnimCamara, null);
		//}
		 
		//01/03
		
		//TODO: cambiar el codigo de "adentro" del SWITCH por un getAnimacionPlano() o getAnimacionEscaleras() (para no repetir codigo)
		//OBS: si es keyframe de nivel, posiblemente tengamos que cambiar 
		//la opacidad de los niveles y reposicionar la camara
		switch (_ESTADO.getTipoAnimacion()){
			case "FROM_ABOVE_STAIRS_COMPLETE_ANIM" : 
			case "FROM_ABOVE_STAIRS_SIMPLE_ANIM":
			case "FROM_ABOVE_NO_STAIRS_ANIM" :
			case "FROM_ABOVE_STAIRS_COMPLETE_ANIM_FOLLOW" :
			case "CHASE_REPOSITION_POINTS" : //TODO VER
				
				puntoTarget.y += PARAMS.distancia_a_objetivo;
				
				var tweenPosicionarCamara = _controlCamaraFly.posicionarCamara( 
									puntoTarget,//posicion	
									0, //rotacion horizontal
									-Math.PI/2, //pitch
									duracionAnimCamara, //duracion
									callback, //primer punto
									climbY);//climbY
				
				if (tweenOpacidad){ tweenOpacidad.start();}
				tweenPosicionarCamara.start();
				
				break;
			case "CHASE_ALL" : //TODO VER	
			case "LOOK_AT": 				
			
				puntoTarget.y += PARAMS.distancia_linea_a_plano;
			
				//por ahora consideramos reposicionar la camara al punto donde esta actualmente la animacion
				//mas un valor "val" en el eje Z (valor heuristico segun implementacion)
				//(ver informe para otra idea para la implementacion)
				var puntoFinalCamara = puntoTarget.clone();//punto de reposicionamiento de la camara
				var val = 500;
				puntoFinalCamara.y += val; 
				puntoFinalCamara.z += val; 
				//
				
				
				//1) animo la orientacion
				//2) animo la posicion
				//3) si (<> nivel) --> animo la opacidad
				//4) callback para seguir animando el resto de los frames
				var tweenOrientacion = _controlCamaraFly.animarOrientacionCamara(puntoTarget, PARAMS.tiempo_posicionamiento_camara, null);	
				var tweenCamaraPosicion = _controlCamaraFly.posicionarCamaraTarget(puntoFinalCamara, puntoTarget, duracionAnimCamara, null);
				tweenOrientacion.chain(tweenCamaraPosicion);
				
				if (tweenOpacidad){ 
					tweenOpacidad.start();
				}
				//else{
					tweenCamaraPosicion.onComplete(callback);
				//}
				
				tweenOrientacion.start();
				
				
				break;
		}//fin switch
	}
	
	
	
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	//este metodo sirve para reposicionar la camara, por ej cuando se clickea un space en el camino (listado div)
	//tipo: "floor" o "space"
	this.reposicionarCamaraFromTree = function(posFinal,nivelesVisibles, nivelesInvisibles, climbY, tipo, callbackFromOutside, animarCamara){
		
		//TODO hacer checkeos
		
		limpiarEsc();//limpiamos la escena
		
		_TWEENER.tweenPlayBack.flushTweens();//tengo que limpiar los Tweens en ejecucion
		callback =  function(){	
			_ESTADO.actualizarEstado("stopped");
			if (callbackFromOutside) callbackFromOutside();
		};
		
		resposCamaraFromTree(posFinal, nivelesVisibles, nivelesInvisibles, callback, climbY, tipo, animarCamara);
	};
	
	
	
	
	var lastNombreNivel = null;
	var lastPoint = null;
	var lastType = null;
	var lastEstado = null;
	
	//reposiciona la camara antes de comenzar una animacion
	//y ejecuta la funcion callback, una vez finalizado el reposicionamiento
	function resposCamaraFromTree(posFinal, nivelesVisibles, nivelesInvisibles, callback, animateYAxis, tipo, animarCamara){
		
		
		
		//01/03
		var puntoTarget = new THREE.Vector3( posFinal.x, posFinal.y, posFinal.z);
		
		_controlCamaraFly = WEBGL.getCameraControls();//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		var duracionAnimCamara = PARAMS.tiempo_posicionamiento_camara;
		var vectorDireccion = puntoTarget.clone(); //TODO para la animacion look at este no es el punto final
		var posCamara = _controlCamaraFly.object.position;
		
		
		vectorDireccion.subSelf(posCamara);
		var dist = vectorDireccion.length();
		
		var climbY = 0;
		if (animateYAxis){
			climbY = (dist/3)^4;
		}
		
		
		if (posCamara.x == puntoTarget.x
				&&	posCamara.y == puntoTarget.y
				&&	posCamara.z == puntoTarget.z
		){
			duracionAnimCamara = 0;
		}else if(dist > 100){
			duracionAnimCamara = dist/PARAMS.velocidadRepCamaraPrincipio;
		}
		
		var tweenOpacidad = null;
		
//		duracionAnimCamara *= 5;
		//console.log("duracionAnimCamara",duracionAnimCamara);
		
		//if (_listaFrames[keyInicial].esKeyFrameNivel){//si estoy en un nivel distinto al que tengo que animar
		//var nombreEdificio = _listaFrames[keyInicial].punteroEdificio;
		//var nombreNivel = _listaFrames[keyInicial].punteroNivel;
		
		//}
		var tweenOpacidad = null;
		if (!animarCamara){
			tweenOpacidad = _TWEENER.tweenBuilder.cambiarOpacidadNiveles(nivelesVisibles, nivelesInvisibles, true, duracionAnimCamara, callback);
			tweenOpacidad.start()
			return;
		}
		
		tweenOpacidad = _TWEENER.tweenBuilder.cambiarOpacidadNiveles(nivelesVisibles, nivelesInvisibles, true, duracionAnimCamara, null);
		
		//01/03
		
		//TODO: cambiar el codigo de "adentro" del SWITCH por un getAnimacionPlano() o getAnimacionEscaleras() (para no repetir codigo)
		//OBS: si es keyframe de nivel, posiblemente tengamos que cambiar 
		//la opacidad de los niveles y reposicionar la camara
		switch (_ESTADO.getTipoAnimacion()){
		case "FROM_ABOVE_STAIRS_COMPLETE_ANIM" : 
		case "FROM_ABOVE_STAIRS_SIMPLE_ANIM":
		case "FROM_ABOVE_NO_STAIRS_ANIM" :
		case "FROM_ABOVE_STAIRS_COMPLETE_ANIM_FOLLOW" :
		case "CHASE_REPOSITION_POINTS" : //TODO VER
			
			var distancia = PARAMS.distancia_a_objetivo;
			if (tipo =="floor"){
				distancia *= 2;
			}else if(tipo == "level"){
				distancia *= 4;
			}
			
			puntoTarget.y += distancia;
			
			var tweenPosicionarCamara = _controlCamaraFly.posicionarCamara( 
					puntoTarget,//posicion final de la camara
					0, //rotacion horizontal
					-Math.PI/2, //pitch
					duracionAnimCamara, //duracion
					callback,//primer punto
					climbY); 
			
			if (tweenOpacidad){ tweenOpacidad.start();}
			tweenPosicionarCamara.start();
			
			break;
		case "CHASE_ALL" : //TODO VER	
		case "LOOK_AT": 				
			
			
			var distancia = PARAMS.distancia_a_objetivo;
			var val = 1000;
			
			var tweenDummy = new TWEEN.Tween({x:1}).to({x:0}, 1);
			
			
			
			
			
			//por ahora consideramos reposicionar la camara al punto donde esta actualmente la animacion
			//mas un valor "val" en el eje Z (valor heuristico segun implementacion)
			//(ver informe para otra idea para la implementacion)
			var puntoFinalCamara = puntoTarget.clone();//punto de reposicionamiento de la camara
			
			
			if (tipo =="floor"){
				distancia *= 1.5;
				puntoFinalCamara.y += 1200; 
				puntoFinalCamara.z += 1700; 							
			}else if(tipo == "level"){
				distancia *= 4;
				puntoFinalCamara.y += 1500; 
				puntoFinalCamara.z += 2500; 
			}else{ //space
				distancia /= 4;
				puntoFinalCamara.y += 500; 
				puntoFinalCamara.z += 700; 
			}
			
			var tweenOrientacion = _controlCamaraFly.animarOrientacionCamara(puntoTarget, PARAMS.tiempo_posicionamiento_camara/3, null);
			var tweenReposLookAt = _controlCamaraFly.posicionarCamaraTarget(puntoFinalCamara, puntoTarget, PARAMS.tiempo_posicionamiento_camara, null);
			
			tweenDummy.onComplete(function(){
				tweenReposLookAt.onComplete(function(){if (callback) callback();});
				tweenOrientacion.chain(tweenReposLookAt);
				tweenOrientacion.start();
				if (tweenOpacidad){	tweenOpacidad.start();}
//				tweenReposLookAt.start();
			});
			
				tweenDummy.start();
			break;
		}//fin switch
		
		
//		lastNombreNivel = nombreNivel;
//		lastPoint = posFinal;
//		lastType = tipo;
//		lastEstado = _ESTADO.getTipoAnimacion();
	}
	
////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////

	
	
	//TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 
	//TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 
	//TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 
	//TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 

	//se llama a este metodo cuando el usuario presiona el boton para generar una nueva busqueda
	//se detiene la animacion actual, y se inhabilitan los controles del panel de reproduccion
	this.nuevaBusquedaEnProceso = function(){
		this.pauseAnimation();
		_UI_PANEL_PLAYBACK.disableButtons();
	};
	
	

	
	
	
	//funcion encargada de generar la animacion de finalizacion de la animacion
	//y setear los parametros para las animaciones subsiguientes
	function finalizarAnimacion(){
		_lineasCreadas.push(_lineaAnimada);				

		//muestro marcador (flecha) en la posicion destino
		if (CONSTANTS.FLECHAS_CAMINO_ENABLED && _ESTADO.estado != "stopped"){
			var tween = _TWEENER.tweenBuilder.getTweenMarcador("final",1000);
			tween.start();
		}
		
		var callback = function(){
			_ESTADO.actualizarEstado("stopped");
			_UI_PANEL_PLAYBACK.updatePlayPauseButton();
			WEBGL.mostrarEscena(true); //TODO
		};
		
		var length = _listaFrames.length;
		if (!length) return;
		
		var indice = length - 1;
		
		//animacion de finalizaci�n
		var tweenAnimacionFinal = null;
		if (_ESTADO.getTipoAnimacion() == "LOOK_AT"){
			
			var puntoTarget = new THREE.Vector3(_listaFrames[indice].x ,
					_listaFrames[indice].z + PARAMS.distancia_linea_a_plano,
					_listaFrames[indice].y );				
											
			var puntoFinalCamara = puntoTarget.clone();//a que punto se reposiciona la camara
			var val = 300;
			puntoFinalCamara.y += val;
			puntoFinalCamara.z += val;
			
			var duracionAnimCamara = PARAMS.tiempo_posicionamiento_camara;
			
			if (_ESTADO.getTipoAnimacionCamara() == "VARIABLE"){	
				var vectorDireccion = puntoFinalCamara.clone();
				vectorDireccion.subSelf(_controlCamaraFly.object.position);
				var dist = vectorDireccion.length();
				duracionAnimCamara = dist/PARAMS.velocidadRepCamara;	
				
				//console.log("dist",dist);
				//console.log("duracionAnimCamara",duracionAnimCamara);
			}
			
			tweenAnimacionFinal = _controlCamaraFly.posicionarCamaraTarget(puntoFinalCamara, puntoTarget, duracionAnimCamara, callback);
		}else{
				var nuevoPunto = new THREE.Vector3(_listaFrames[indice].x, _listaFrames[indice].z +200 , _listaFrames[indice].y + 200);
				tweenAnimacionFinal = _controlCamaraFly.posicionarCamara(nuevoPunto, 0, -Math.PI/4, PARAMS.tiempo_posicionamiento_camara,callback);
		}
		
		
		if (tweenAnimacionFinal){tweenAnimacionFinal.start();}
		else {callback();}
	}
	
	
	
	
	
	//coordenadas X = X, Y = Z, Z = Y. TODO
	//<indice> : indica el punto que estoy dibujando actualmente
	function animarKeyframe(indice){
	
		var indiceInicial = 0;//indiceInicial sera realmente necesario cuando tengamos que partir la linea animada (por ahora esta demas)
		var indiceFinal = _listaFrames.length;
		
		if (indice == null){alert('ERROR. indice == null');}	
		
		_TWEENER.tweenPlayBack.cleanTweensArray();
		//_TWEENER.tweenPlayBack.flushTweens();
		_ESTADO.frameActual = indice;
			
		
		if (indice < indiceFinal){	

			//variable que mantendra la posicion del punto actual (se animara el segmento de recta 
			// desde el punto anterior al punto actual)
			var verticeActual = null;

			//remuevo la linea correspondiente a la anicacion hasta el punto anterior
			//OBS: esto es debido a que no se pueden generar arreglos dinamicos (VBO)
			//y aunque se pudiera (si THREE.js lo permitiera), resultaria tan caro como hacer esto
			if (_lineaAnimada) _scene.remove(_lineaAnimada);

			//creo la geometria para la linea, y le agrego los vertices hasta el anterior al actual
			var geo_lineaAnimada = new THREE.Geometry();					
			for (var i = indiceInicial; i< indice; i++){
				verticeActual = new THREE.Vertex (new THREE.Vector3(_listaFrames[i].x, _listaFrames[i].z + PARAMS.distancia_linea_a_plano,_listaFrames[i].y));
				geo_lineaAnimada.vertices.push(verticeActual);
			}
			
			//guardo x e y del punto anterior (indice - 1)
			var x_old = verticeActual.position.x;
			var y_old = verticeActual.position.z;
			var z_old = verticeActual.position.y;
			var positionOld = new THREE.Vector3(x_old, z_old, y_old);
			var positionNew = new THREE.Vector3(_listaFrames[indice].x, _listaFrames[indice].z, _listaFrames[indice].y);
			
			//el punto actual comenzara la animacion con las coordenadas del punto anterior
			//y a medida que avance la animacion, se ira actualizando su posicion, hasta
			//arribar a la posicion final
			verticeActual = new THREE.Vertex (positionOld);

			//agrego el punto actual al arreglo de vertices
			geo_lineaAnimada.vertices.push(verticeActual);

			//calculo la distancia desde el punto anterior y al actual,
			//para setear la velocidad de la animacion de este segmento (asi la velocidad es 
			// lineal para toda la polilinea)
			var distancia =  positionOld.distanceTo(positionNew); //distanceTo de THREE.Vector3

			//creo el objeto 3D que representa a la linea
			_lineaAnimada = new THREE.Line( geo_lineaAnimada,  MATERIAL_BUILDER.getMaterial("linea_camino"));
			
			//agrego la linea al objeto 3D del piso
			_scene.add(_lineaAnimada);

			var duracionTrayecto = (distancia/PARAMS.velocidadLinea);
			
			//actulizo el slider que indica por que space voy pasando
			if (_listaFrames[indice].esKeyFrameSpace){
				_PANEL_CAMINOS.updateSelection(indice);	
			}
			
			
			var tweenTrayecto = null;
			var tweenOpacidad = null;//solo se da para los casos en que tengamos un keyframe de nivel
			
			//obtenemos el tipo de animacion dependiendo si el space es una escalera o una space comun 
			if (_listaFrames[indice].tipo == "escalera"){				
				tweenTrayecto = _TWEENER.tweenBuilder.getAnimacionEscaleras(indice, duracionTrayecto, verticeActual);
			}			
			else{//si no es 'escalera' 
				tweenTrayecto = _TWEENER.tweenBuilder.getAnimacionPlano(indice, duracionTrayecto, verticeActual);							
			};

			
			//si es keyframe de nivel, tengo que animar la opacidad de los niveles actual y anterior			
			if (_listaFrames[indice].esKeyFrameNivel){
				var nombreEdificio = _listaFrames[indice].punteroEdificio;
				var nombreNivel = _listaFrames[indice].punteroNivel;
				tweenOpacidad = _TWEENER.tweenBuilder.cambiarOpacidadNiveles(nombreEdificio, nombreNivel, true, PARAMS.tiempo_posicionamiento_camara, null);
				
				if (_ESTADO.getTipoAnimacion() == "CHASE_ALL"){ //no me detengo, sigo animando la linea y la opacidad cambia en paralelo
					tweenTrayecto.start();
					tweenOpacidad.start();
				}else{
					tweenOpacidad.chain(tweenTrayecto);
					tweenOpacidad.start();
				}
			}else{
				if (!tweenTrayecto) alert("ERROR. tweenTrayecto UNDEFINED");
				tweenTrayecto.start();
			}
			
			_lineasCreadas.push(_lineaAnimada);	
			
			
		}else{ //TERMINAMOS DE ANIMAR LA LINEA
			finalizarAnimacion();
		}
	};
	
	
	//<indice> : indica el punto que estoy dibujando actualmente
	function animarKeyframeSimulado(indice){
		
		var indiceInicial = 0;//indiceInicial sera realmente necesario cuando tengamos que partir la linea animada (por ahora esta demas)
		var indiceFinal = _listaFrames.length;
		
		_TWEENER.tweenPlayBack.cleanTweensArray();
		//_TWEENER.tweenPlayBack.flushTweens();
		_ESTADO.frameActual = indice;
				
		if (indice < indiceFinal){	
			
			//variable que mantendra la posicion del punto actual (se animara el segmento de recta 
			// desde el punto anterior al punto actual)
			var verticeActual = null;
			
			//remuevo la linea correspondiente a la anicacion hasta el punto anterior
			//OBS: esto es debido a que no se pueden generar arreglos dinamicos (VBO)
			//y aunque se pudiera (si THREE.js lo permitiera), resultaria tan caro como hacer esto
			if (_lineaAnimada) _scene.remove(_lineaAnimada);
			
			//creo la geometria para la linea, y le agrego los vertices hasta el anterior al actual
			var geo_lineaAnimada = new THREE.Geometry();					
			for (var i = indiceInicial; i<= indice; i++){
				verticeActual = new THREE.Vertex (new THREE.Vector3(_listaFrames[i].x, _listaFrames[i].z + PARAMS.distancia_linea_a_plano,_listaFrames[i].y));
				geo_lineaAnimada.vertices.push(verticeActual);
				
				//pinto las escaleras como "visitadas"
				if (_listaFrames[i].tipo == "escalera"){	
					_TWEENER.tweenBuilder.restaurarEscalera(i, CONSTANTS.COLOR_ESCALON_ANIMADO);
					//_listaFrames[i].punteroNodo.animarColorTween(CONSTANTS.COLOR_ESCALON_ANIMADO /*CONSTANTS.COLOR_ESCALON_ANIMADO = var global */);
				}	
				
				//si es keyframe de nivel, tengo que animar la opacidad de los niveles actual y anterior			
				if (_listaFrames[i].esKeyFrameNivel){
					var nombreEdificio = _listaFrames[i].punteroEdificio;
					var nombreNivel = _listaFrames[i].punteroNivel;
					_TWEENER.tweenBuilder.cambiarOpacidadNiveles(nombreEdificio, nombreNivel, false, PARAMS.tiempo_posicionamiento_camara, null);
				}
			}					
			
			//creo el objeto 3D que representa a la linea
			//console.log('MATERIAL_BUILDER.getMaterial("linea_camino")',MATERIAL_BUILDER.getMaterial("linea_camino"));
			_lineaAnimada = new THREE.Line( geo_lineaAnimada,  MATERIAL_BUILDER.getMaterial("linea_camino"));						
			
			//agrego la linea al objeto 3D del piso
			_scene.add(_lineaAnimada);
			
			_lineasCreadas.push(_lineaAnimada);	
			
		}else{ 
			//terminamos de agregar los _listaFrames de la polilinea que se encuentran dentro del 'path'
			//para un determinado '_listaFrames_index' (_listaFrames dentro de un mismo piso). 
			_lineasCreadas.push(_lineaAnimada);				
			
			//como queremos que el segmento de linea permanezca cuando pasemos a animar otro segmento
			//en otro piso, seteamos la linea dinamica a NULL
//			_lineaAnimada = null;
			if (CONSTANTS.FLECHAS_CAMINO_ENABLED && _ESTADO.estado != "stopped"){
				var tween = _TWEENER.tweenBuilder.getTweenMarcador("final",0);
				tween.start();
			}
			
			_ESTADO.actualizarEstado("stopped");
			
		}
	};




	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- PREPROCESAMIENTO DEL CAMINO A ANIMAR --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	
	//TODO, funcion para que ande
	//junta los puntos para generar la linea de un conjunto de pisos a un mismo nivel
	function procesarCamino(camino){
		
		var ultimoNivel = null;//(camino.length>0)? camino[0].level : null;
		var ultimoNombreSpace = null;//(camino.length>0 && (camino[0].puntos.length >0))? camino[0].puntos[0].nombre : null;//control para juntar todos los puntos de un space
		var length_camino = camino.length;
		
		var camino_i = null;
		
		//recorremos todas las lineas que conforman la polilinea
		for (var i = 0; i< length_camino; i++){
  			
			camino_i = camino[i];
  			if (camino_i.tipo != "plano"){ continue;}; //TODO para detectar los de tipo portal
  			
  			var componentes = camino_i.id.split("\/"); //spliteo el string con el caracter '/'
  			var nivel = camino_i.level;
  			var nombreEdificio = componentes[0];
  			var nombrePiso = componentes[1];
  			
			//recorremos los puntos de la linea dentro de un dado piso
			for (var j = 0, length_puntos = camino_i.puntos.length;  j< length_puntos ; j++){
				
				var keyframe = camino[i].puntos[j];

				keyframe.esKeyFrameNivel = false;
				keyframe.esKeyFramePiso = false;
				keyframe.esKeyFrameSpace = false;
				keyframe.punteroEdificio = nombreEdificio;
				keyframe.punteroNivel = nivel;
				keyframe.punteroPiso = nombrePiso;
				keyframe.punteroNodo = null; //puede apuntar tanto a un space como a un portal
				
				
				//evaluo si es keyframe de nivel
				if (nivel != ultimoNivel){
					
					keyframe.esKeyFrameNivel = true;
					ultimoNivel = nivel;
				}
				
				//evaluo si es keyframe de piso
				if (j == 0){
					keyframe.esKeyFramePiso = true;
					keyframe.punteroPiso =  nombreEdificio+"/"+nombrePiso;
						//_nodos[nombreEdificio][nombrePiso];
				}
				
				//evaluo si es keyframe de space
				if (keyframe.nombre != ultimoNombreSpace){
					keyframe.esKeyFrameSpace = true;
					ultimoNombreSpace = keyframe.nombre;
					switch(keyframe.tipo){
						case "space" : 
							//TODO por el momento, 'punteroNodo' no se usa
							keyframe.punteroNodo = nombreEdificio+"/"+nombrePiso+"/"+"spaces"+"/"+keyframe.nombre;
								//_nodos[nombreEdificio][nombrePiso]["spaces"][keyframe.nombre];
							break;
						
						case "escalera": 
							
							var sourceSpaceName = camino[i].puntos[j-1].nombre; //TODO ver cuando venga con ID el camino
							if (camino[i].puntos.length <= j+1) alert('error, revisar... dibujador caminos, escaleras. ioob');//TODO
							var targetSpaceName = camino[i].puntos[j+1].nombre;//se supone que va a estar en el mismo piso y edificio
							
							//pregunto al controlador cual es el id del portal que une a los spaces
							var portalID = CONTROLLER_JERARQUIA_SPACES.getPortalID(nombreEdificio, nombrePiso, sourceSpaceName, targetSpaceName);
							keyframe.punteroNodo = portalID;	
							
							if (keyframe.punteroNodo == null)
								alert('error, revisar... dibujador caminos, escaleras. keyframe.punteroNodo == null');//TODO
							
							break;
					}
					
				}
				_listaFrames.push(keyframe);
			}
  		}
		
		if(length_camino){ _ESTADO.frameActual = 0;}
		
		//console.log("_listaFrames______________",_listaFrames);
		
	}//+++ fin procesarCamino
	
}; /*fin controller_playback*/